NDK探究之旅《十一》—C代码调用Java代码之项目实战
C代码调用Java代码步骤及其注意事项
博客地址:
C代码调用Java代码步骤及其注意事项
今天我们来探究一下C语言是如何调用Java代码的
我们先来看一下Java代码是如何调用C代码的
那C代码是如何调用Java代码的呢?
C调用Java中的方法
其实就是从java中调用c,从C中调用java的方法,可以看做是一个回调
Java中没有参数的方法
1.在java中写一个本地方法
public native void methodInC();
2.使用命令提示符进入到项目下的bin/classes目录下,使用javah 类的全路径 命令得到本地方法的头文件
3.在项目上点右键-->Android Tools-->Add Native Support,给我们的C代码起一个名字,点确定,会自动生成一个jni的目录和c代码(一般生成的是.cpp,把后缀改为.c)
4.自动生成的Android.mk文件中的编译源文件是.cpp,改为c(如果第三步没有改,则不需要改)
#指定编译的文件夹 指定当前文件目录
LOCAL_PATH := $(call my-dir)
#编译器会定义很多的临时变量,中间变量,最好清空所有的中间变量。
include $(CLEAR_VARS)
#编译出来模块的名称(编译后的名字,也就是存放于libs目录下的名字,不带扩展名)
LOCAL_MODULE := hello
# 编译的源代码的名称(要编译的c代码的名称,带扩展名)
LOCAL_SRC_FILES := hello.c
#编译一个动态库
include $(BUILD_SHARED_LIBRARY)
5.如果需要在除arm处理器的其它机型上使用,需要在jni目录下创建一个Application.mk文件(如果只是在arm下使用,可以跳过此步骤),需要哪一个处理器,就配置哪一个,不要配置太多,因为生成的文件会很大
APP_ABI := arm x86 mips
6.把ndk安装的目录下的android-ndk-r9b\platforms\android-16\arch-arm\usr\include/jni.h复制到项目的jni目录下(平台就现在版本没有任何区别,哪一个版本下的都可以) 7.写C代码
#include <jni.h>
#include "stdio.h"
#include "com_itheima_calljava_DataProvider.h"
/**
* 用C代码调用java代码中的方法,去发送一条短信
*/
JNIEXPORT void JNICALL Java_com_demo_calljava_DataProvider_methodInC
(JNIEnv* env, jobject obj){
//第一步:找到要调用的方法的class字节码文件
jclass clazz = (*env)->FindClass(env,"com/itheima/calljava/DataProvider");
//第二步:找到这个类中的方法.参数依次为:JVM虚拟机环境、class对象、方法名、方法签名(返回值+方法的形参)
jmethodID mid = (*env)->GetMethodID(env,clazz,"methodInjava","()V");
//第三步:调用这个方法
(*env)->CallVoidMethod(env,obj,mid);
}
8.在要调用本地方法的类中使用静态代码块的方式加载生成的c代码库
static{
//这个名字是在Android.mk中的LOCAL_MODULE的值,不带前缀,不带扩展名
System.loadLibrary("hello");
}
9.只要在java中调用本地方法methodInC即可
注: Java中的被C调用的方法
/**
* 让C调用此方法,发送一条短信
*/
public void methodInjava(){
Log.i(TAG,"-------------------------");
//创建短信管理对象
SmsManager smsManager = SmsManager.getDefault();
//发送一条文本短信
smsManager.sendTextMessage("5556", null, "hello 5556", null, null);
}
如何去获取方法的签名
Javap -s com.包名.类名
如:
Demo相关示例:
C语言调用Java中的方法去Toast吐司和Log日志打印
相关代码:
public class ServiceProvider {
public void methodInJavaSource(){
System.out.print("-------->我来了");
LogUtil.e("yuyahao","-------->我来了");
for (int i = 0; i < 20; i++) {
GetToast.useString(MyApplication.getInstance(),"C代码来调用我啦啦啦..."+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 调用C代码,让C代码再次调用Java代码
*/
public native void callFromCMethod();
}
MainActivity
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("serviceData");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Class service = getClassLoader().loadClass("jni.yyh.com.mycptojavanative.jni.ServiceProvider");
Method method = service.getMethod("methodInJavaSource",new Class []{});
method.invoke(service.newInstance(),new Object[]{});
//调用其方法
} catch (Exception e) {
e.printStackTrace();
}
findViewById(R.id.btn_onclick).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ServiceProvider serviceProvider = new ServiceProvider();
serviceProvider.callFromCMethod();
}
});
}
}
主要的就是C代码:
#include <stdio.h>
#include"jni_yyh_com_mycptojavanative_jni_ServiceProvider.h"
#include <android/log.h>
#include"jni.h"
#define LOG_TAG "System.out.c"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
//java中调用c代码,直接调用native方法即可。
JNIEXPORT void Java_jni_yyh_com_mycptojavanative_jni_ServiceProvider_callFromCMethod(JNIEnv * env, jobject obj){
char * pageName = "jni/yyh/com/mycptojavanative/jni/ServiceProvider";
//第一步,首先找到Java 中的class对象
jclass clzz = (*env)->FindClass(env,pageName);
//第二步,找到class里面的一个方法
jmethodID methodid = (*env)->GetMethodID(env,clzz,"methodInJavaSource","()V");
int ss = 0;
LOGD("pagename=%d");
LOGI("pagename=%s",pageName);
//第三步调用clas里面的一个方法
(*env)->CallVoidMethod(env,obj,methodid);
}
相关Demo下载地址:
C语言调用Java方法进行Toast吐司和Log日志进行打印
博客地址:
NDK探究之旅:
NDK探究之旅《十》——ndk项目实战之Androidstudio开发经验总结
Hello,伙伴们